package com.agentframework.core.annotation;

import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.*;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.util.StringUtils;

import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 配置和启动扫描器
 * 负责创建和配置 ClassPathAgentScanner，并执行扫描
 */
public class AgentScannerConfigurer implements BeanDefinitionRegistryPostProcessor {

    private String basePackage;
    private BeanNameGenerator nameGenerator;

    public void setBasePackage(String basePackage) {
        this.basePackage = basePackage;
    }

    public BeanNameGenerator getNameGenerator() {
        return this.nameGenerator;
    }

    public void setNameGenerator(BeanNameGenerator nameGenerator) {
        this.nameGenerator = nameGenerator;
    }

    @Override
    public void postProcessBeanDefinitionRegistry(@NotNull BeanDefinitionRegistry registry) {
        List<AbstractClassPathScanner> classPathScanners = getClassPathScanners(registry);

        Map<Class<? extends Annotation>, Map<String, BeanDefinition>> scannedBeansMap = classPathScanners.stream()
                .map(AbstractClassPathScanner::getScannedBeans)
                .collect(ConcurrentHashMap::new, Map::putAll, Map::putAll);

        processDependencies(scannedBeansMap, registry);

    }

    @NotNull
    private List<AbstractClassPathScanner> getClassPathScanners(@NotNull BeanDefinitionRegistry registry) {
        List<AbstractClassPathScanner> classPathScanners = List.of(new ActionClassPathScanner(registry), new AgentClassPathScanner(registry), new EnvironmentClassPathScanner(registry));

        classPathScanners.forEach(scanner -> {
            scanner.registerFilters();

            if (nameGenerator != null) {
                scanner.setBeanNameGenerator(nameGenerator);
            }

            if (StringUtils.hasText(basePackage)) {
                scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
            }
        });
        return classPathScanners;
    }

    private void processDependencies(Map<Class<? extends Annotation>, Map<String, BeanDefinition>> scannedBeans, BeanDefinitionRegistry registry) {
        // 1. 处理 Action 到 Agent 的依赖
        processActionToAgentDependencies(scannedBeans, registry);

        // 2. 处理 Agent 到 Environment 的依赖
        processAgentToEnvironmentDependencies(scannedBeans, registry);
    }

    private void processActionToAgentDependencies(Map<Class<? extends Annotation>, Map<String, BeanDefinition>> scannedBeans, BeanDefinitionRegistry registry) {
        Map<String, BeanDefinition> actionBeans = scannedBeans.get(Action.class);
        Map<String, BeanDefinition> agentBeans = scannedBeans.get(Agent.class);

        if (actionBeans != null && agentBeans != null) {
            for (Map.Entry<String, BeanDefinition> entry : agentBeans.entrySet()) {
                BeanDefinition agentDef = entry.getValue();
                if (agentDef instanceof AnnotatedBeanDefinition annotatedDef) {
                    // 获取 Agent 注解
                    AnnotationAttributes agentAttrs = AnnotationAttributes.fromMap(annotatedDef.getMetadata().getAnnotationAttributes(Agent.class.getName()));

                    // 获取 actions 属性
                    Class<?>[] actions = agentAttrs.getClassArray("actions");

                    // 为每个 Agent 添加 Action 引用
                    for (Class<?> actionClass : actions) {
                        String actionBeanName = getBeanNameFromClass(actionClass, registry);
                        BeanDefinition actionDef = actionBeans.get(actionBeanName);
                        if (actionDef != null) {
                            addActionToAgent(agentDef, actionBeanName);
                        }
                    }
                }
            }
        }
    }

    private void addActionToAgent(BeanDefinition agentDef, String actionBeanName) {
        Object existing = agentDef.getPropertyValues().get("actions");
        ManagedList<Object> actions;
        if (existing instanceof ManagedList) {
            actions = (ManagedList<Object>) existing;
        } else {
            actions = new ManagedList<>();
        }
        actions.add(new RuntimeBeanReference(actionBeanName));
        agentDef.getPropertyValues().add("actions", actions);
    }

    private void processAgentToEnvironmentDependencies(Map<Class<? extends Annotation>, Map<String, BeanDefinition>> scannedBeans, BeanDefinitionRegistry registry) {
        Map<String, BeanDefinition> agentBeans = scannedBeans.get(Agent.class);
        Map<String, BeanDefinition> environmentBeans = scannedBeans.get(Environment.class);

        if (environmentBeans != null && agentBeans != null) {
            for (Map.Entry<String, BeanDefinition> entry : environmentBeans.entrySet()) {
                BeanDefinition envDef = entry.getValue();
                if (envDef instanceof AnnotatedBeanDefinition annotatedDef) {
                    // 获取 Environment 注解
                    AnnotationAttributes envAttrs = AnnotationAttributes.fromMap(annotatedDef.getMetadata().getAnnotationAttributes(Environment.class.getName()));

                    // 获取 agents 属性
                    Class<?>[] agents = envAttrs.getClassArray("agents");

                    // 为每个 Environment 添加 Agent 引用
                    for (Class<?> agentClass : agents) {
                        String agentBeanName = getBeanNameFromClass(agentClass, registry);
                        BeanDefinition agentDef = agentBeans.get(agentBeanName);
                        if (agentDef != null) {
                            if (agentDef.getScope().equals(Agent.Scope.PROTOTYPE.name().toLowerCase())) {
                                // 标识为原型prototype的agent不设置bean
                                continue;
                            }
                            addAgentToEnvironment(envDef, agentBeanName);
                        }
                    }
                }
            }
        }
    }

    private void addAgentToEnvironment(BeanDefinition envDef, String agentBeanName) {
        Object existing = envDef.getPropertyValues().get("agents");
        ManagedList<Object> agents;
        if (existing instanceof ManagedList) {
            agents = (ManagedList<Object>) existing;
        } else {
            agents = new ManagedList<>();
        }
        agents.add(new RuntimeBeanReference(agentBeanName));
        envDef.getPropertyValues().add("agents", agents);
    }

    private String getBeanNameFromClass(Class<?> clazz, BeanDefinitionRegistry registry) {
        return AnnotationBeanNameGenerator.INSTANCE.generateBeanName(
                BeanDefinitionBuilder.genericBeanDefinition(clazz).getBeanDefinition(),
                registry
        );
    }

    @Override
    public void postProcessBeanFactory(@NotNull ConfigurableListableBeanFactory beanFactory) {
        // 不需要实现
    }

}